//
// MessagePack for C++ static resolution routine
//
// Copyright (C) 2014-2015 KONDO Takatoshi
//
//    Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//    http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef MSGPACK_V1_TYPE_CPP11_BITSET_HPP
#define MSGPACK_V1_TYPE_CPP11_BITSET_HPP

#include "msgpack/versioning.hpp"
#include "msgpack/adaptor/adaptor_base.hpp"
#include "msgpack/adaptor/check_container_size.hpp"

#include <bitset>

//
// 对于64位以内的bitset用 unsigned long long 转换,效率高，节省数据量
// 对于64位以上的bitset用 string 转换，支持任意长度的bitset
//

namespace msgpack {

/// @cond
MSGPACK_API_VERSION_NAMESPACE(v1) {
/// @endcond

namespace adaptor {

template <std::size_t N>
struct convert<std::bitset<N>> {
    msgpack::object const& operator()(msgpack::object const& o, std::bitset<N>& v) const {
		std::string str;
		switch (o.type) {
			case msgpack::type::BIN:
				str.assign(o.via.bin.ptr,o.via.bin.size);
				v = std::bitset<N>(str);
				break;
			case msgpack::type::STR:
				str.assign(o.via.str.ptr,o.via.str.size);
				v = std::bitset<N>(str);
				break;
			case msgpack::type::POSITIVE_INTEGER:
				if (N > 64){throw msgpack::type_error();}
				v = std::bitset<N>(type::detail::convert_integer<unsigned long long>(o));
				break;
			default:
				throw msgpack::type_error();
				break;
		}
		return o;
    }
};

template <>
struct convert<std::bitset<0>> {
    msgpack::object const& operator()(msgpack::object const& o, std::bitset<0>&) const {
        return o;
    }
};

template <std::size_t N>
struct pack<std::bitset<N>> {
    template <typename Stream>
    msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const std::bitset<N>& v) const {
		if (N > 64) {	/*大于64位用string*/
			std::string str = v.to_string();
			uint32_t size = checked_get_container_size(str.size());
			o.pack_str(size);
			o.pack_str_body(str.data(),size);
		} else {
			o.pack_unsigned_long_long(v.to_ullong());
		}
        return o;
    }
};

template <std::size_t N>
struct object<std::bitset<N>> {
    void operator()(msgpack::object& o, const std::bitset<N>& v) const {
		if (N > 64) {
			std::string str = v.to_string();
			uint32_t size =  checked_get_container_size(str.size());
			o.type = msgpack::type::STR;
			o.via.str.ptr = str.data();
			o.via.str.size = size;
		} else {
			o.type = msgpack::type::POSITIVE_INTEGER;
			o.via.u64 = v.to_ullong();
		}
    }
};

template <std::size_t N>
struct object_with_zone<std::bitset<N>> {
	void operator()(msgpack::object::with_zone& o, const std::bitset<N>& v) const {
		if ( N > 64) {
			std::string str = v.to_string();
			uint32_t size = checked_get_container_size(str.size());
			o.type = msgpack::type::STR;
			char* ptr = static_cast<char*>(o.zone.allocate_align(size, MSGPACK_ZONE_ALIGNOF(char)));
			o.via.str.ptr = ptr;
			o.via.str.size = size;
			std::memcpy(ptr, str.data(), str.size()); 
		} else {
			static_cast<msgpack::object&>(o) << v.to_ullong();
		}
    }
};

} // namespace adaptor

/// @cond
} // MSGPACK_API_VERSION_NAMESPACE(v1)
/// @endcond

} // namespace msgpack

#endif // MSGPACK_V1_TYPE_CPP11_BITSET_HPP
